﻿using System;
using System.Data;
using System.Globalization;
using System.Windows.Forms;
using SQLDiagConfiguration.Properties;

namespace SQLDiagConfiguration
{
    /// <summary>
    /// This class implements common functionality of the various pages
    /// Displayed in the Select a Page Pane
    /// </summary>
    public partial class BasePage : UserControl
    {
        #region Properties
        // Progress dialog for long tree rebuilds
        public Progress progress { get; set; }

        // This object holds state for all pages
        private DiagInfoObject diagInfo;

        public DiagInfoObject DiagInfo
        {
            get { return diagInfo; }
            set { diagInfo = value; }
        }
        //If the page is not editable, no need to SaveState
        private bool isEditable = true;

        public bool IsEditable
        {
            get { return isEditable; }
            set { isEditable = value; }
        }
        #endregion Properties

        #region Constructor
        public BasePage()
        {
            InitializeComponent();
        }
        #endregion Constructor

        #region Methods to Load and Save to configuration file
        /// <summary>
        /// Meta-data about each control and how it is mapped to the element
        /// and attributes is contained in the Tag property of each control
        /// </summary>
        public virtual void SaveState()
        {
            // No need to process if not editable (i.e. Welcome Page)
            if (isEditable == true)
            {
                foreach (Control c in this.Controls)
                {
                    // If the control has a tag then we need to save it's state using that tag information
                    if (c.Tag != null)
                    {
                        SaveControlState(c);
                    }
                    // If no tag, it may be a groupbox and we need to look into that collection 
                    // to process the controls that have tag information
                    else if (c.GetType().Name == Resources.strGroupBox)
                    {
                        foreach (Control c1 in c.Controls)
                        {
                            if (c1.Tag != null)
                            {
                                SaveControlState(c1);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// This method encapsulates the saving of all controls, except for the TreeView controls
        /// which are handled in separate methods on those specific pages
        /// </summary>
        /// <param name="o"></param>
        private void SaveControlState(Control o)
        {
            // Each tag is a triplet of values
            // tag[0] = Element Name
            // tag[1] = row number
            // tag[2] = Attribute Name
            if (o != null)
            {
                string[] tags = o.Tag.ToString().Split(',');
                int rowNumber = Convert.ToInt32(tags[1], CultureInfo.CurrentCulture);
                // Now based on the control type, extract the information in a way that makes sense
                // for that control type and save it to our DataSet for eventual saving to a file
                System.Type t = o.GetType();
                switch (t.Name)
                {
                    case "RadioButton":
                        RadioButton rb = (RadioButton)o;
                        DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]] = rb.Checked == true ? "true" : "false";
                        break;
                    case "CheckBox":
                        CheckBox cb = (CheckBox)o;
                        DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]] = cb.Checked == true ? "true" : "false";
                        break;
                    case "TextBox":
                        TextBox tb = (TextBox)o;
                        DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]] = tb.Text;
                        break;
                    case "ComboBox":
                        ComboBox combo = (ComboBox)o;
                        DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]] = combo.Text;
                        break;
                }
            }
        }
        /// <summary>
        /// Meta-data about each control and how it is mapped to the element
        /// and attributes is contained in the Tag property of each control
        /// </summary>
        public virtual void LoadState()
        {
            // No need to process if not editable (i.e. Welcome Page)
            if (IsEditable == true)
            {
                foreach (Control c in this.Controls)
                {
                    // If the control has a tag then we need to load it's state using that tag information
                    if (c.Tag != null)
                    {
                        LoadControlState(c);
                    }
                    // If no tag, it may be a groupbox and we need to look into that collection 
                    // to process the controls that have tag information
                    else if (c.GetType().Name == Resources.strGroupBox)
                    {
                        foreach (Control c1 in c.Controls)
                        {
                            if (c1.Tag != null)
                            {
                                LoadControlState(c1);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// This method encapsulates the loading of all controls, except for the TreeView controls
        /// which are handled in separate methods on those specific pages
        /// </summary>
        /// <param name="ctl"></param>
        public void LoadControlState(Control ctl)
        {
            // Each tag is a triplet of values
            // tag[0] = Element Name
            // tag[1] = row number
            // tag[2] = Attribute Name
            if (ctl != null)
            {
                string[] tags = ctl.Tag.ToString().Split(',');
                int rowNumber = Convert.ToInt16(tags[1],CultureInfo.CurrentCulture);
                System.Type t = ctl.GetType();
                // Now based on the control type, set the information in a way that makes sense
                // for that control type by retrieving it from our DataSet 
                switch (t.Name)
                {
                    case "RadioButton":
                        RadioButton rb = (RadioButton)ctl;
                        rb.Checked = DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]].ToString() == "true" ? true : false;
                        break;
                    case "CheckBox":
                        CheckBox cb = (CheckBox)ctl;
                        cb.Checked = DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]].ToString() == "true" ? true : false;
                        break;
                    case "TextBox":
                        TextBox tb = (TextBox)ctl;
                        tb.Text = DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]].ToString();
                        break;
                    case "ComboBox":
                        ComboBox combo = (ComboBox)ctl;
                        int i = combo.FindString(DiagInfo.SQLDiagConfigDataSet.Tables[tags[0]].Rows[rowNumber][tags[2]].ToString());
                        combo.SelectedIndex = i;
                        break;
                }
            }
        }
        #endregion Methods to Load and Save to configuration file

        #region Helper Methods
        /// <summary>
        /// This method is used to update the values for the child rows enabled column
        /// </summary>
        /// <param name="ds">The new dataset</param>
        /// <param name="parentTable">Which key defines the parent identifer</param>
        /// <param name="childTable">and which defines the children identifer</param>
        /// <param name="relationName">what is the name of the DataRelation between parent and child</param>
        /// <param name="keyName">The name of the column that we what to match the child records on</param>
        public void UpdateNodes(DataSet ds, string parentTable, string childTable, string relationName, string keyName)
        {
            if (ds != null)
            {
                // Create local variables to save typing
                // This represents the tree as it current is
                DataTable newParent = ds.Tables[parentTable];
                DataTable newChild = ds.Tables[childTable];
                DataRelation parentChildRelationship = ds.Relations[relationName];
                
                // And let's only look up our resource strings once
                string enabledColumnName = Resources.strEnabled;

                // Now create local variables for the new nodes for the tree
                DataSet currentDataSet = DiagInfo.SQLDiagConfigDataSet;
                DataTable currentParentTable = currentDataSet.Tables[parentTable];
                DataTable currentChildTable = currentDataSet.Tables[childTable];
                DataRelation currentPCRelationship = currentDataSet.Relations[relationName];

                // We need to let the user know we are doing a bunch of work
                Progress p = new Progress(currentChildTable.Rows.Count > newChild.Rows.Count ? currentChildTable.Rows.Count : newChild.Rows.Count);
                p.Show();
                // We do not expect any changes to the parents so we just choose to use the new
                // dataset values
                // Go through each new parent row
                foreach (DataRow r in newParent.Rows)
                {
                    // Get a row - i.e Broker Events from the current table
                    DataRow selectedParentRow = currentParentTable.Rows.Find(r[keyName].ToString());
                    // this should never be null, but...
                    if (selectedParentRow != null)
                    {
                        // determine the number of children that the current row and new row have
                        int currentChildCount = selectedParentRow.GetChildRows(currentPCRelationship).Length;
                        int newChildCount = r.GetChildRows(parentChildRelationship).Length;

                        // if current >= new then we already have all the rows, we just need to update the values
                        if (currentChildCount >= newChildCount)
                        {
                            // so loop through all the current child rows, and look for the matched new child row
                            foreach (DataRow selectedChildRow in selectedParentRow.GetChildRows(currentPCRelationship))
                            {
                                // Build our filter string
                                string colName = selectedChildRow.Table.Columns[0].ColumnName;
                                string key = colName + "='" + selectedChildRow[colName].ToString() + "'";

                                // and search both new and current tables for that row
                                DataRow[] selectedCurrentChildRow = currentChildTable.Select(key);
                                DataRow[] selectedNewChildRow = newChild.Select(key);

                                // Because we know the number of children match we can safely copy 
                                // the Enabled value from new to old
                                // if the new fragment doesn't have the same number of children as the current
                                if (selectedNewChildRow.Length != 0)
                                {
                                    selectedCurrentChildRow[0][enabledColumnName] = selectedNewChildRow[0][enabledColumnName];
                                }
                                // bump the progress bar
                                p.Increment();
                            }
                        }
                        else
                        // new fragment has more children then we need to copy values for the ones that match
                        // and add the new ones that we don't yet have in the collection.
                        if (newChildCount > currentChildCount)
                        {
                            // So here we process in the reverse order that we did above
                            // i.e. here we get the new children and locate all the current matches
                            // if we don't have a match then we add the new child to the current child table
                            // by calling ImportRow
                            foreach (DataRow selectedNewChildRow2 in r.GetChildRows(parentChildRelationship))
                            {
                                string colName = selectedNewChildRow2.Table.Columns[0].ColumnName;
                                string key = colName + "='" + selectedNewChildRow2[colName].ToString() + "'";
                                DataRow[] selectedCurrentChildRow = currentChildTable.Select(key);
                                DataRow[] selectedNewChildRows = newChild.Select(key);
                                // Even though there are more new - this one matches
                                // so copy the value
                                if (selectedCurrentChildRow.Length == 1 && selectedNewChildRows.Length == 1)
                                {
                                    selectedCurrentChildRow[0][enabledColumnName] = selectedNewChildRows[0][enabledColumnName];
                                    p.Increment();
                                }
                                else
                                {
                                    // This is a child row that wasn't in the current children
                                    // but the new children had a row, so let's add it to the current children
                                    currentChildTable.ImportRow(selectedNewChildRow2);
                                    p.Increment();
                                }
                            }
                        }
                    }
                }
                // We are done, so remove the Progress dialog
                p.Close();
            }
        }
        public virtual void LoadControlText()
        {
            // Allow derived Pages to load their control texts
        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Allow derived pages to load their control's text from resource file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BasePage_Load(object sender, EventArgs e)
        {
            LoadControlText();
        }
        #endregion Event Handlers
    }
}
